package com.ice.demo.generic;

import java.util.ArrayList;
import java.util.List;

/**
 * <? extends T> – 上界通配符，表示“T 或 T 的子类”，只读不写（安全取出）。
 * <? super T>   – 下界通配符，表示“T 或 T 的父类”，只写不读（安全插入）。
 * 记住口诀：PECS – Producer extends，Consumer super。
 */
public class GenericTest {
    public static void main(String[] args) {

        // extends 拿来取数据，super 拿来放数据；

        /**
         * // 把 src 元素拷贝到 dest
         * public static <T> void copy(List<? extends T> src,   // 生产元素 → extends
         *                             List<? super T>   dest) { // 消费元素 → super
         *     for (T t : src) dest.add(t);
         * }
         *
         *
         * List<Integer>  src  = List.of(1, 2);
         * List<Number>   dest = new ArrayList<>();
         * copy(src, dest);   // ✅ 编译通过
         *
         */

        List<Integer> ints = List.of(1, 2, 3);

        // 1. 上界 extends：只能取，不能放
        List<? extends Number> ext = ints;
        Number n = ext.get(0);   // ✅ 安全
//        Integer sn = ext.get(1);
        /**
         * ext.get(1) 的编译期类型是 ? extends Number，
         * 编译器只知道它是 Number 或 Number 的某个子类，但无法确定具体是哪一个（可能是 Integer、Double、BigDecimal……）。
         * 因此：
         * 把 ? extends Number 直接赋给 Integer 需要向下强转，而泛型通配符环境下编译器禁止这种不安全的强转（除非你自己显式 cast）。
         * 赋给 Number 是安全的，因为 Number 是明确的上界。
         */

        // ext.add(3);           // ❌ 编译失败，不知道具体类型
        /**
         *还是同一个根源：编译器根本不知道 ext 的具体类型参数是哪一个。
         * 变量定义
         * java
         * 复制
         * List<? extends Number> ext = ints;
         * 此时 ext 的实际类型是 List<Integer>，但引用类型被擦写为 List<CAP#1>，其中
         * CAP#1 是某个未知的 Number 子类，它只读不写。
         * 向 ext 执行 add(Integer.valueOf(1)) 时，编译器要检查元素类型是否匹配那个未知的 CAP#1。
         * 因为无法确定 CAP#1 一定是 Integer（也可能是 Double、BigDecimal 等），
         * 所以任何具体类型的实参都不能通过检查——包括 Integer、Double 甚至 Number 本身。
         * 结果：编译失败，提示
         * add (CAP#1) in List cannot be applied to (Integer)
         * 换句话说：
         * “? extends Number” 是生产者视角，只能往外读，不能往里写（除了 null）。
         * 这就是 PECS 里的 Producer extends 含义。
         * 若想安全地插入，必须把引用类型改成 下界通配符：
         * java
         * 复制
         * List<? super Integer> dest = new ArrayList<Number>();
         * dest.add(Integer.valueOf(1));   // ✅ 编译通过
         * 结论：
         * ? extends T 保证取出的东西至少是 T，但拒绝任何写入；
         * 想写入就用 ? super T，它保证写入的东西至少是 T 的子类。
         */
//        ext.add(Integer.valueOf(1));
        ext.add(null); // 仅仅null可以写入

        // 2. 下界 super：只能放，取出的东西最弱是 Object
        List<? super Number> sup = new ArrayList<Number>();
        sup.add(Long.parseLong("1.23"));              // ✅ 安全
        sup.add(Integer.valueOf(1));              // ✅ 安全
        // Integer i = sup.get(0); // ❌ 返回 Object，需强转
        Object o = sup.get(0);   // ✅

    }
}
